#include "../bulk_storage/bulk_storage.h"
#include "xyz.h"

#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <errno.h>

double xyz_float_distance(const struct xyz_float * a, const struct xyz_float * b) {
  float x = a->x - b->x; 
  float y = a->y - b->y;  
  float z = a->z - b->z;  
    
  double d = (double)(x*x + y*y + z*z);
  
  return sqrt(d);
}
double xyz_double_distance(const struct xyz_double * a, const struct xyz_double * b) {
  double x = a->x - b->x; 
  double y = a->y - b->y;  
  double z = a->z - b->z;  
    
  double d = (double)(x*x + y*y + z*z);
  return sqrt(d);
}
double  xyz_short_distance(const struct xyz_short * a, const struct xyz_short * b) {
  double x = a->x - b->x; 
  double y = a->y - b->y;  
  double z = a->z - b->z;  
    
  double d = (x*x + y*y + z*z);
  //  assert(d > =0);
  return sqrt(d);
}
double    xyz_int_distance(const struct xyz_int * a, const struct xyz_int * b) {
  double x = (double)a->x - (double)b->x; 
  double y = (double)a->y - (double)b->y;  
  double  z = (double)a->z - (double)b->z;  

  double d = (double)(x*x + y*y + z*z);
  //  assert(d > =0);

  return sqrt(d);
  
}
double    xyz_long_distance(const struct xyz_long * a, const struct xyz_long * b) {
  long x = a->x - b->x; 
  long y = a->y - b->y;  
  long z = a->z - b->z;  
    
  double d = (double)(x*x + y*y + z*z);
  return sqrt(d);
}


double xyz_float_manhattan_distance(const struct xyz_float *a, const struct xyz_float *b) {
  return (double) fabsf(a->x - b->x) + fabsf(a->y - b->y) + fabsf(a->z - b->z);
}
double xyz_double_manhattan_distance(const struct xyz_double *a, const struct xyz_double *b) {
  return fabs(a->x - b->x) + fabs(a->y - b->y) + fabs(a->z - b->z);
}
double xyz_long_manhattan_distance(const struct xyz_long *a, const struct xyz_long *b) {
  return (double) labs(a->x - b->x) + labs(a->y - b->y) + labs(a->z - b->z);
}
double xyz_int_manhattan_distance(const struct xyz_int *a, const struct xyz_int *b) {
  return (double) abs(a->x - b->x) + abs(a->y - b->y) + abs(a->z - b->z);
}
double xyz_short_manhattan_distance(const struct xyz_short *a, const struct xyz_short *b) {
  return (double) abs(a->x - b->x) + abs(a->y - b->y) + abs(a->z - b->z);
}

double xyz_float_chessboard_distance(const struct xyz_float *a, const struct xyz_float *b) {

  float dx = fabsf(a->x - b->x);
  float dy = fabsf(a->y - b->y);
  float dz = fabsf(a->z - b->z);
  
  if(dx > dy && dx > dz) {
    return (double) dx;
  } else if (dy > dz) {
    return (double) dy;
  } else {
    return (double) dz;
  }

}
double xyz_double_chessboard_distance(const struct xyz_double *a, const struct xyz_double *b) {

  double dx = fabs(a->x - b->x);
  double dy = fabs(a->y - b->y);
  double dz = fabs(a->z - b->z);
  
  if(dx > dy && dx > dz) {
    return dx;
  } else if (dy > dz) {
    return dy;
  } else {
    return dz;
  }

}
double xyz_long_chessboard_distance(const struct xyz_long *a, const struct xyz_long *b) {

  long dx = labs(a->x - b->x);
  long dy = labs(a->y - b->y);
  long dz = labs(a->z - b->z);
  
  if(dx > dy && dx > dz) {
    return (double) dx;
  } else if (dy > dz) {
    return (double) dy;
  } else {
    return (double) dz;
  }

}
double xyz_int_chessboard_distance(const struct xyz_int *a, const struct xyz_int *b) {

  int dx = abs(a->x - b->x);
  int dy = abs(a->y - b->y);
  int dz = abs(a->z - b->z);
  
  if(dx > dy && dx > dz) {
    return (double) dx;
  } else if (dy > dz) {
    return (double) dy;
  } else {
    return (double) dz;
  }

}
double xyz_short_chessboard_distance(const struct xyz_short *a, const struct xyz_short *b) {

  short dx = abs(a->x - b->x);
  short dy = abs(a->y - b->y);
  short dz = abs(a->z - b->z);
  
  if(dx > dy && dx > dz) {
    return (double) dx;
  } else if (dy > dz) {
    return (double) dy;
  } else {
    return (double) dz;
  }

}


double xyz_float_p_norm_distance(const struct xyz_float *a, const struct xyz_float *b, const double p) {
  return pow( pow(fabs((double)(a->x - b->x)), p) + pow(fabs((double)(a->y - b->y)), p) + pow((double)(fabs(a->z - b->z)), p)
	  , 1/p);
}
double xyz_double_p_norm_distance(const struct xyz_double *a, const struct xyz_double *b, const double p) {
  return pow( pow(fabs((double)(a->x - b->x)), p) + pow(fabs((double)(a->y - b->y)), p) + pow((double)(fabs(a->z - b->z)), p)
	  , 1/p);
}
double xyz_long_p_norm_distance(const struct xyz_long *a, const struct xyz_long *b, const double p) {
  return pow( pow(fabs((double)(a->x - b->x)), p) + pow(fabs((double)(a->y - b->y)), p) + pow((double)(fabs(a->z - b->z)), p)
	  , 1/p);
}
double xyz_int_p_norm_distance(const struct xyz_int *a, const struct xyz_int *b, const double p) {
  return pow( pow(fabs((double)(a->x - b->x)), p) + pow(fabs((double)(a->y - b->y)), p) + pow((double)(fabs(a->z - b->z)), p)
	  , 1/p);
}
double xyz_short_p_norm_distance(const struct xyz_short *a, const struct xyz_short *b, const double p) {
  return pow( pow(fabs((double)(a->x - b->x)), p) + pow(fabs((double)(a->y - b->y)), p) + pow((double)(fabs(a->z - b->z)), p)
	  , 1/p);
}


const struct xyz_float * xyz_float_print(const struct xyz_float * a, FILE * out) {
  fprintf(out, "(%f, %f, %f)", a->x, a->y, a->z);
  return a;
}
const struct xyz_double * xyz_double_print(const struct xyz_double * a, FILE * out) {
  fprintf(out, "(%f, %f, %f)", a->x, a->y, a->z);
  return a;
}
const struct xyz_short * xyz_short_print(const struct xyz_short * a, FILE * out) {
  fprintf(out, "(%d, %d, %d)", a->x, a->y, a->z);
  return a;
}
const struct xyz_int * xyz_int_print(const struct xyz_int * a, FILE * out) {
  fprintf(out, "(%d, %d, %d)", a->x, a->y, a->z);
  return a;
}
const struct xyz_long * xyz_long_print(const struct xyz_long * a, FILE * out) {
  fprintf(out, "(%ld, %ld, %ld)", a->x, a->y, a->z);
  return a;
}

